/*
-------------------------------------------------

	Common.cpp

	Dmitriy Kuzmenko (Dgut)

-------------------------------------------------
*/

#include "Common.h"
#include "Audio.h"
#include "Autumn.h"
#include "Console.h"
#include "File.h"
#include "Game.h"
#include "Input.h"
#include "Render.h"
#include "UI.h"
#include "XML.h"

#if defined IPHONE
#include <sys/time.h>
#elif defined WIN32
#include <windows.h>
#include <gl/gl.h>
#endif

namespace Autumn
{

Common::Common( void ) :
	DELTA		( 0 ),
	TIME		( 0 ),
	WIDTH		( 0 ),
	HEIGHT		( 0 ),
	IPAD		( false ),
	pause		( false )
{
}

Common::~Common( void )
{
}

const int Common::Milliseconds( void )
{
#if defined IPHONE
	timeval tv;
	static int start = 0;
	
	gettimeofday( &tv, 0 );
	
	if( !start )
	{
		start = tv.tv_sec;
		return tv.tv_usec / 1000;
	}
	
	return ( tv.tv_sec - start ) * 1000 + tv.tv_usec / 1000;
#elif defined WIN32
	return timeGetTime();
#endif
}

const bool Common::Init( void )
{
#if defined IPHONE
	const_cast< bool & >( IPAD ) = [ [ UIDevice currentDevice ].model rangeOfString : @"iPad" ].location != NSNotFound;
#endif

	srand( Milliseconds() );

	if( !gFile.Init() )
		return false;
	if( !gConsole.Init() )
		return false;
	if( !gAudio.Init() )
		return false;
	if( !gRender.Init() )
		return false;
	if( !gInput.Init() )
		return false;
	if( !gUI.Init() )
		return false;

	pGame = CreateGame();

	if( !gGame.Init() )
		return false;

	Load();
	
	return true;
}

void Common::Shutdown( void )
{
	Save();

	if( pGame )
		gGame.Shutdown();

	delete pGame;

	gUI.Shutdown();
	gInput.Shutdown();
	gRender.Shutdown();
	gAudio.Shutdown();
	gConsole.Shutdown();
	gFile.Shutdown();

	exit( 0 );
}

void Common::Frame( void )
{
	static int oldTime = Milliseconds(), newTime = 0;
	
	int & delta = const_cast< int & >( DELTA );
	
	if( pause )
	{
		oldTime = Milliseconds();
		pause = false;
	}
	
	do
	{
		newTime = Milliseconds();
		delta = newTime - oldTime;
	}
	while( delta < 1 );

	const_cast< int & >( TIME ) += delta;

	gInput.Frame();
	gAudio.Frame();
	gRender.Frame();
	gUI.Frame();
	gInput.Save();

	oldTime = newTime;
}

void Common::Resize( int width, int height )
{
	const_cast< int & >( WIDTH ) = width;
	const_cast< int & >( HEIGHT ) = height;

	glViewport( 0, 0, width, height );
}

void Common::Pause( void )
{
	pause = true;
}

void Common::Save( void )
{
	pugi::xml_document game;

	pugi::xml_node node = game.append_child( pugi::node_element );
	node.set_name( "game" );
	node.append_attribute( "version" ).set_value( VERSION );
	node.append_attribute( "sound" ).set_value( gAudio.IsSoundEnable() );
	node.append_attribute( "music" ).set_value( gAudio.IsMusicEnable() );

#if defined IPHONE
	node.append_attribute( "udid" ).set_value( [ [ UIDevice currentDevice ].uniqueIdentifier UTF8String ] );
#endif

	if( pGame )
		gGame.Save( node );

	gXML.Save( &game, "game.xml", true );
}

const bool Common::Load( void )
{
	pugi::xml_document * game;
	if( !( game = gXML.Load( "game.xml", true ) ) )
		return false;

	pugi::xml_node node = game->child( "game" );

	gAudio.SoundEnable( node.attribute( "sound" ).as_bool() );
	gAudio.MusicEnable( node.attribute( "music" ).as_bool() );
	
#if defined IPHONE
	if( strcmp( node.attribute( "udid" ).value(), [ [ UIDevice currentDevice ].uniqueIdentifier UTF8String ] ) )
	{
		delete game;
		return false;
	}
#endif
	
	int version = node.attribute( "version" ).as_int();
	/*if( version < VERSION )
	{
		delete game;
		return false;
	}*/

	gGame.Load( node );

	delete game;
	
	return true;
}

}	// namespace Autumn